{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7765UFHoyGx6"
      },
      "source": [
        "##### Copyright 2019 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "KVtTDrUNyL7x"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "xPYxZMrWyA0N"
      },
      "source": [
        "# Деревья решений с использованием оценщиков(Estimators)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "p_vOREjRx-Y0"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://www.tensorflow.org/tutorials/estimator/boosted_trees\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\" />Смотреть на TensorFlow.org</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ru/tutorials/estimator/boosted_trees.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" />Запустить в Google Colab</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ru/tutorials/estimator/boosted_trees.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\">Смотреть исходные файлы на GitHub</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/ru/tutorials/estimator/boosted_trees.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\" />Скачать ноутбук</a>\n",
        "  </td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8a2322303a3f"
      },
      "source": [
        "Note: Вся информация в этом разделе переведена с помощью русскоговорящего Tensorflow сообщества на общественных началах. Поскольку этот перевод не является официальным, мы не гарантируем что он на 100% аккуратен и соответствует [официальной документации на английском языке](https://www.tensorflow.org/?hl=en). Если у вас есть предложение как исправить этот перевод, мы будем очень рады увидеть pull request в [tensorflow/docs](https://github.com/tensorflow/docs) репозиторий GitHub. Если вы хотите помочь сделать документацию по Tensorflow лучше (сделать сам перевод или проверить перевод подготовленный кем-то другим), напишите нам на [docs-ru@tensorflow.org list](https://groups.google.com/a/tensorflow.org/forum/#!forum/docs-ru)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "dW3r7qVxzqN5"
      },
      "source": [
        "Это раздел представляет собой сквозное пошаговое руководство по обучению модели градиентного бустинга с использованием деревьев решений с помощью `tf.estimator`. Модели Boosted Trees являются одним из самых популярных и эффективных подходов к машинному обучению как для регрессии, так и для классификации. Это техника ансамбля, которая объединяет прогнозы из нескольких(например, 10, 100 или даже 1000) моделей решающих деревьев.\n",
        "\n",
        "Модели Boosted Trees популярны среди многих практиков машинного обучения, поскольку они могут достичь впечатляющей производительности с минимальной настройкой гиперпараметров."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "eylrTPAN3rJV"
      },
      "source": [
        "## Загрузка датасета пассажиров Титаника\n",
        "\n",
        "Вы будете использовать набор данных \"Титаник\", цель которого(довольно болезненная) - предсказать выживаемость пассажиров с учетом таких характеристик, как пол, возраст, класс и т.д."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "KuhAiPfZ3rJW"
      },
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "import pandas as pd\n",
        "from IPython.display import clear_output\n",
        "from matplotlib import pyplot as plt\n",
        "\n",
        "# Загружаем датасет.\n",
        "dftrain = pd.read_csv('https://storage.googleapis.com/tf-datasets/titanic/train.csv')\n",
        "dfeval = pd.read_csv('https://storage.googleapis.com/tf-datasets/titanic/eval.csv')\n",
        "y_train = dftrain.pop('survived')\n",
        "y_eval = dfeval.pop('survived')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "NFtnFm1T0kMf"
      },
      "outputs": [],
      "source": [
        "import tensorflow as tf\n",
        "tf.random.set_seed(123)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3ioodHdVJVdA"
      },
      "source": [
        "Набор данных состоит из обучающего и тестового набора:\n",
        "\n",
        "* `dftrain` и` y_train` - это *обучающий датасет* - данные, которые модель использует для обучения.\n",
        "* Модель протестирована с использованием *тестового датасета* - `dfeval` и` y_eval`.\n",
        "\n",
        "Для обучения вы будете использовать следующие возможности:\n",
        "\n",
        "\n",
        "<table>\n",
        "  <tr>\n",
        "    <th> Название функции </th>\n",
        "    <th> Описание </th>\n",
        "  </tr>\n",
        "  <tr>\n",
        "    <td> sex </td>\n",
        "    <td> Пол пассажира </td>\n",
        "  </tr>\n",
        "  <tr>\n",
        "    <td> age </td>\n",
        "    <td> Возраст пассажира </td>\n",
        "  </tr>\n",
        "    <tr>\n",
        "    <td> n_siblings_spouses </td>\n",
        "    <td> братья, сестры и супргуи на борту </td>\n",
        "  </tr>\n",
        "    <tr>\n",
        "    <td> parch </td>\n",
        "    <td> родители и дети на борту </td>\n",
        "  </tr>\n",
        "    <tr>\n",
        "    <td> fare </td>\n",
        "    <td> Тариф пассажира </td>\n",
        "  </tr>\n",
        "    <tr>\n",
        "    <td> class </td>\n",
        "    <td> Класс пассажира на корабле </td>\n",
        "  </tr>\n",
        "    <tr>\n",
        "    <td> deck </td>\n",
        "    <td> На какой палубе находился пассажир </td>\n",
        "  </tr>\n",
        "    <tr>\n",
        "    <td> embark_town </td>\n",
        "    <td> В каком городе пассажир совершил посадку </td>\n",
        "  </tr>\n",
        "    <tr>\n",
        "    <td> alone </td>\n",
        "    <td> Был ли пассажир один </td>\n",
        "  </tr>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "AoPiWsJALr-k"
      },
      "source": [
        "## Изучение данных"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "slcat1yzmzw5"
      },
      "source": [
        "Давайте сначала просмотрим некоторые данные и создадим сводную статистику по обучающей выборке."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "15PLelXBlxEW"
      },
      "outputs": [],
      "source": [
        "dftrain.head()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "j2hiM4ETmqP0"
      },
      "outputs": [],
      "source": [
        "dftrain.describe()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-IR0e8V-LyJ4"
      },
      "source": [
        "В обучающей и тестовой выборках 627 и 264 примеров соответственно."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "_1NwYqGwDjFf"
      },
      "outputs": [],
      "source": [
        "dftrain.shape[0], dfeval.shape[0]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "28UFJ4KSMK3V"
      },
      "source": [
        "Большинство пассажиров в возрасте от 20 до 30 лет."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "CaVDmZtuDfux"
      },
      "outputs": [],
      "source": [
        "dftrain.age.hist(bins=20)\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1pifWiCoMbR5"
      },
      "source": [
        "Пассажиров-мужчин примерно в два раза больше, чем пассажиров-женщин."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "-WazAq30MO5J"
      },
      "outputs": [],
      "source": [
        "dftrain.sex.value_counts().plot(kind='barh')\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7_XkxrpmmVU_"
      },
      "source": [
        "Большинство пассажиров находились в «третьем» классе."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "zZ3PvVy4l4gI"
      },
      "outputs": [],
      "source": [
        "dftrain['class'].value_counts().plot(kind='barh')\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HM5SlwlxmZMT"
      },
      "source": [
        "Большинство пассажиров сели в Саутгемптоне."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "RVTSrdr4mZaC"
      },
      "outputs": [],
      "source": [
        "dftrain['embark_town'].value_counts().plot(kind='barh')\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "aTn1niLPob3x"
      },
      "source": [
        "У женщин намного больше шансов выжить, чем у мужчин. Это явно будет прогностическим признаком модели."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Eh3KW5oYkaNS"
      },
      "outputs": [],
      "source": [
        "pd.concat([dftrain, y_train], axis=1).groupby('sex').survived.mean().plot(kind='barh').set_xlabel('% survive')\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "krkRHuMp3rJn"
      },
      "source": [
        "## Создание столбцов признаков и функций ввода\n",
        "\n",
        "Эстиматор Gradient Boosting может использовать как числовые, так и категориальные признаки. Столбцы признаков работают со всеми эстиматорами TensorFlow, и их цель - определить признаки, используемые для моделирования. Кроме того, они предоставляют некоторые возможности разработки функций, такие как `one-hot-encoding`, `нормализация` и `разделение на пакеты`. В этом руководстве поля в `CATEGORICAL_COLUMNS` преобразуются из категориальных столбцов в `one-hot-encoding` столбцы ([столбец индикатора](https://www.tensorflow.org/api_docs/python/tf/feature_column/indicator_column)):"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "upaNWxcF3rJn"
      },
      "outputs": [],
      "source": [
        "CATEGORICAL_COLUMNS = ['sex', 'n_siblings_spouses', 'parch', 'class', 'deck',\n",
        "                       'embark_town', 'alone']\n",
        "NUMERIC_COLUMNS = ['age', 'fare']\n",
        "\n",
        "def one_hot_cat_column(feature_name, vocab):\n",
        "  return tf.feature_column.indicator_column(\n",
        "      tf.feature_column.categorical_column_with_vocabulary_list(feature_name,\n",
        "                                                 vocab))\n",
        "feature_columns = []\n",
        "for feature_name in CATEGORICAL_COLUMNS:\n",
        "  # Нужно перобразовать категориальные признаки в числовые с помощью `one-hot-encoding` метода.\n",
        "  vocabulary = dftrain[feature_name].unique()\n",
        "  feature_columns.append(one_hot_cat_column(feature_name, vocabulary))\n",
        "\n",
        "for feature_name in NUMERIC_COLUMNS:\n",
        "  feature_columns.append(tf.feature_column.numeric_column(feature_name,\n",
        "                                           dtype=tf.float32))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "74GNtFpStSAz"
      },
      "source": [
        "Вы можете просмотреть преобразование, выполненное над признаками. Например, вот результат использования `indicator_column` в одном примере:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Eaq79D9FtmF8"
      },
      "outputs": [],
      "source": [
        "example = dict(dftrain.head(1))\n",
        "class_fc = tf.feature_column.indicator_column(\n",
        "    tf.feature_column.categorical_column_with_vocabulary_list('class', ('First', 'Second', 'Third')))\n",
        "print('Feature value: \"{}\"'.format(example['class'].iloc[0]))\n",
        "print('One-hot encoded: ', tf.keras.layers.DenseFeatures([class_fc])(example).numpy())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YbCUn3nCusC3"
      },
      "source": [
        "Кроме того, вы можете просматривать все преобразования признаков вместе:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "omIYcsVws3g0"
      },
      "outputs": [],
      "source": [
        "tf.keras.layers.DenseFeatures(feature_columns)(example).numpy()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-UOlROp33rJo"
      },
      "source": [
        "Далее вам нужно создать функции ввода. Они укажут, как данные будут считываться в нашу модель как для обучения, так и для вывода. Вы будете использовать метод `from_tensor_slices` из [`tf.data`](https://www.tensorflow.org/api_docs/python/tf/data) для чтения данных непосредственно из Pandas. Это подходит для небольших наборов данных, умещающихся в памяти. Для больших наборов данных `tf.data`  поддерживает различные форматы файлов(включая [csv](https://www.tensorflow.org/api_docs/python/tf/data/experimental/make_csv_dataset)), чтобы вы могли обрабатывать наборы данных которые не помещаются в памяти."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "9dquwCQB3rJp"
      },
      "outputs": [],
      "source": [
        "# Используйте весь пакет, так как это небольшой набор данных.\n",
        "NUM_EXAMPLES = len(y_train)\n",
        "\n",
        "def make_input_fn(X, y, n_epochs=None, shuffle=True):\n",
        "  def input_fn():\n",
        "    dataset = tf.data.Dataset.from_tensor_slices((dict(X), y))\n",
        "    if shuffle:\n",
        "      dataset = dataset.shuffle(NUM_EXAMPLES)\n",
        "    # Для обучения повторите набор данных столько раз, сколько потребуется(n_epochs = None).\n",
        "    dataset = dataset.repeat(n_epochs)\n",
        "    # При обучении на датасете, помещающимся в памяти нет необходимости в разделении на пакеты.\n",
        "    dataset = dataset.batch(NUM_EXAMPLES)\n",
        "    return dataset\n",
        "  return input_fn\n",
        "\n",
        "# Функции ввода для обучения и оценки.\n",
        "train_input_fn = make_input_fn(dftrain, y_train)\n",
        "eval_input_fn = make_input_fn(dfeval, y_eval, shuffle=False, n_epochs=1)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HttfNNlN3rJr"
      },
      "source": [
        "## Обучение и оценка модели\n",
        "\n",
        "Далее проделайте следующие шаги:\n",
        "\n",
        "1. Инициализируйте модель, указав функции и гиперпараметры.\n",
        "2. Загрузите обучающие данные в модель с помощью `train_input_fn` и обучите модель с помощью функции `train`.\n",
        "3. Вы будете оценивать производительность модели, используя оценочный набор - в этом примере DataFrame `dfeval`. Вы должны убедится, что прогнозы соответствуют меткам из массива `y_eval`.\n",
        "\n",
        "Перед обучением модели Boosted Trees давайте сначала обучим линейный классификатор (модель логистической регрессии). Лучше всего начать с более простой модели, чтобы иметь отправную точку."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "JPOGpmmq3rJr"
      },
      "outputs": [],
      "source": [
        "linear_est = tf.estimator.LinearClassifier(feature_columns)\n",
        "\n",
        "# Обучение.\n",
        "linear_est.train(train_input_fn, max_steps=100)\n",
        "\n",
        "# Оценка.\n",
        "result = linear_est.evaluate(eval_input_fn)\n",
        "clear_output()\n",
        "print(pd.Series(result))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "BarkNXwA3rJu"
      },
      "source": [
        "Теперь давайте обучим модель Boosted Trees. Для решающих деревьев поддерживаются регрессия(`BoostedTreesRegressor`) и классификация(`BoostedTreesClassifier`). Поскольку цель - предсказать класс - выживет пассажир или нет, вы будете использовать `BoostedTreesClassifier`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "tgEzMtlw3rJu"
      },
      "outputs": [],
      "source": [
        "# Поскольку данные помещаются в память, используйте весь набор данных для каждого слоя. Так будет быстрее.\n",
        "# Выше мы определили размер пакета равным размеру всего датасета.\n",
        "n_batches = 1\n",
        "est = tf.estimator.BoostedTreesClassifier(feature_columns,\n",
        "                                          n_batches_per_layer=n_batches)\n",
        "\n",
        "# Модель прекратит обучение после того, как будет построено указанное \n",
        "# количество деревьев, а не количество шагов.\n",
        "est.train(train_input_fn, max_steps=100)\n",
        "\n",
        "# Оценка.\n",
        "result = est.evaluate(eval_input_fn)\n",
        "clear_output()\n",
        "print(pd.Series(result))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hEflwznXvuMP"
      },
      "source": [
        "Теперь вы можете использовать обученную модель, чтобы делать прогнозы относительно пассажиров из тестового датасета. Модели TensorFlow могут делать прогнозы для пакета, коллекции или единичного примера. Ранее мы определили использование всего тестового датасета для`eval_input_fn`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "6zmIjTr73rJ4"
      },
      "outputs": [],
      "source": [
        "pred_dicts = list(est.predict(eval_input_fn))\n",
        "probs = pd.Series([pred['probabilities'][1] for pred in pred_dicts])\n",
        "\n",
        "probs.plot(kind='hist', bins=20, title='predicted probabilities')\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mBUaNN1BzJHG"
      },
      "source": [
        "И наконец, вы можете посмотреть на ROC-кривую, позволяющий оценить качество нашей классификации."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "NzxghvVz3rJ6"
      },
      "outputs": [],
      "source": [
        "from sklearn.metrics import roc_curve\n",
        "\n",
        "fpr, tpr, _ = roc_curve(y_eval, probs)\n",
        "plt.plot(fpr, tpr)\n",
        "plt.title('ROC curve')\n",
        "plt.xlabel('false positive rate')\n",
        "plt.ylabel('true positive rate')\n",
        "plt.xlim(0,)\n",
        "plt.ylim(0,)\n",
        "plt.show()"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "name": "boosted_trees.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
